
#ifndef __LIBERTY_LIBRARY_ABSTRACTMUTEXPROVIDER_H__
#define __LIBERTY_LIBRARY_ABSTRACTMUTEXPROVIDER_H__

#include <boost/smart_ptr/detail/spinlock.hpp>
#include <Liberty3D/Library/IMutex.h>
#include <Liberty3D/Library/ISharedLock.h>
#include <Liberty3D/Library/IExclusiveLock.h>

namespace Liberty { namespace Library { namespace Mutex {
    namespace Impl { namespace Abstract {
        class Mutex;
        class MutexProvider;
        class UniqueLock;
        class UpgradableLock;
        class UpgradedLock;

        template <typename MutexType>     class MutexImpl;
        template <typename MutexProvider> class MutexImplProvider;

        class UpgradableLock {
        protected:
            std::unique_ptr<ISharedLock> _lock;

        public:
            template <typename T>
            inline UpgradableLock(T& mutex) : _lock(mutex.lockShared()) {
            }

            template <typename T>
            inline UpgradableLock(T* mutex) : _lock(mutex->lockShared()) {
            }

            template <typename T>
            inline UpgradableLock(const std::shared_ptr<T>& mutex) : _lock(mutex->lockShared()) {
            }

            inline ISharedLock* lockShared() const { return _lock.get(); }
        };

        class UniqueLock {
        protected:
            std::unique_ptr<IExclusiveLock> _lock;

        public:
            template <typename T>
            inline UniqueLock(T& mutex) : _lock(mutex.lock()) {
            }

            template <typename T>
            inline UniqueLock(T* mutex) : _lock(mutex->lock()) {
            }

            template <typename T>
            inline UniqueLock(const std::shared_ptr<T>& mutex) : _lock(mutex->lock()) {
            }
        };

        class UpgradedLock {
        protected:
            std::unique_ptr<IExclusiveLock> _lock;

        public:
            inline UpgradedLock(ISharedLock& lock) : _lock(lock.upgrade()) {
            }

            inline UpgradedLock(ISharedLock* lock) : _lock(lock->upgrade()) {
            }

            inline UpgradedLock(const std::unique_ptr<ISharedLock>& lock) : _lock(lock->upgrade()) {
            }

            inline UpgradedLock(UpgradableLock& lock) : _lock(lock.lockShared()->upgrade()) {
            }
        };

        class Mutex : public std::shared_ptr<ISharedMutex> {
        public:
            inline Mutex() {
            }

            inline Mutex(const std::shared_ptr<ISharedMutex>& mutex) : std::shared_ptr<ISharedMutex>(mutex) {
            }

            inline Mutex(const Mutex& mutex) : std::shared_ptr<ISharedMutex>(mutex) {
            }

            IExclusiveLock* lock() {
                return (*this)->lock();
            }

            ISharedLock* lockShared() {
                return (*this)->lockShared();
            }
        };

        template <typename MutexType>
        class MutexImpl : public Mutex {
        public:
            inline MutexImpl() : Mutex(new MutexType()) {
            }

            inline MutexImpl(const std::shared_ptr<ISharedMutex>& mutex) : Mutex(mutex) {
            }

            inline MutexImpl(const MutexImpl& mutex) : Mutex(mutex) {
            }
        };
    }}

    class Abstract {
    public:
        typedef Liberty::Library::Mutex::Impl::Abstract::Mutex                Mutex;
        typedef Liberty::Library::Mutex::Impl::Abstract::UpgradableLock       SharedLock;
        typedef Liberty::Library::Mutex::Impl::Abstract::UniqueLock           UniqueLock;
        typedef Liberty::Library::Mutex::Impl::Abstract::UpgradableLock       UpgradableLock;
        typedef Liberty::Library::Mutex::Impl::Abstract::UpgradedLock         UpgradedLock;
    };

    template <typename MutexType>
    class AbstractImpl {
    public:
        typedef Liberty::Library::Mutex::Impl::Abstract::MutexImpl<MutexType> Mutex;
        typedef Liberty::Library::Mutex::Impl::Abstract::UpgradableLock       SharedLock;
        typedef Liberty::Library::Mutex::Impl::Abstract::UniqueLock           UniqueLock;
        typedef Liberty::Library::Mutex::Impl::Abstract::UpgradableLock       UpgradableLock;
        typedef Liberty::Library::Mutex::Impl::Abstract::UpgradedLock         UpgradedLock;
    };
}}}

#endif
